Problemas de regressão envolvem a predição de um valor numérico contínuo a partir de um conjunto de característiacs.

Neste exemplo, vamos construir um modelo para prever preços de casas a partir de características delas, como número de quartos e taxa de crimes na localização da casa.

Leitura dos dados

Usaremos o pacote pandas para ler os dados.

Pandas é uma biblioteca de código aberto que permite a leitura de dados a partir de diversos formatos para uma estrutura tabular que pode ser acessada e processada por scripts Python.


In [1]:
# Testando se a biblioteca está instalada corretamente e consegue ser importada
import pandas as pd

Neste exercício, usaremos o dataset Boston Housinh para prever preços de casas a partir de características delas e de sua vizinhança.


In [2]:
# Carregue o arquivo 'datasets/boston.csv' usando o pandas

Pandas permite a leitura de nossos dados a partir de diferentes formatos. Veja esse link para uma lista de formatos suportados e as respectivas funções usadas para lê-los.

O tipo usado pelo pandas para representar essa tabela com nosso dataset carregado é chamada de DataFrame.


In [ ]:
# Use o método head() para exibir as primeiras cinco linhas do dataset

O método head() imprime as primeiras cinco linhas por padrão. Ele pode receber opcionalmente um argumento que especifique quantas linhas devem ser exibidas, como boston.head(n=10).


In [ ]:
# Use o método info() para exibir algumas informações sobre o dataset

O método info() exibe vários detalhes sobre o dataset, como a sua quantidade de linhas, quais features estão presentes, qual é o tipo de cada feature e se existem valores em branco.


In [ ]:
# Use o método describe() apra exibir algumas estatísticas do dataset

O método describe() apenas mostra estatísticas de features numéricas. Se uma feature contém strings, por exemplo, ele não será capaz de mostrar informações sobre ela.

Visualização de dados

Após ler os dados em um DataFrame do pandas e ter obtido uma visão geral do dataset, podemos criar gráficos para visualizar o "formato" desses dados.

Usaremos a biblitoeca Matplotlib para criar esses gráficos.

Exemplo

Suponha que lhe seja dada a seguinte informação sobre quatro datasets:


In [4]:
datasets = pd.read_csv('./datasets/anscombe.csv')

for i in range(1, 5):
    dataset = datasets[datasets.Source == 1]
    print('Dataset {} (X, Y) mean: {}'.format(i, (dataset.x.mean(), dataset.y.mean())))

print('\n')
for i in range(1, 5):
    dataset = datasets[datasets.Source == 1]
    print('Dataset {} (X, Y) std deviation: {}'.format(i, (dataset.x.std(), dataset.y.std())))

print('\n')
for i in range(1, 5):
    dataset = datasets[datasets.Source == 1]
    print('Dataset {} correlation between X and Y: {}'.format(i, dataset.x.corr(dataset.y)))


Dataset 1 (X, Y) mean: (9.0, 7.500909090909093)
Dataset 2 (X, Y) mean: (9.0, 7.500909090909093)
Dataset 3 (X, Y) mean: (9.0, 7.500909090909093)
Dataset 4 (X, Y) mean: (9.0, 7.500909090909093)


Dataset 1 (X, Y) std deviation: (3.3166247903554, 2.031568135925815)
Dataset 2 (X, Y) std deviation: (3.3166247903554, 2.031568135925815)
Dataset 3 (X, Y) std deviation: (3.3166247903554, 2.031568135925815)
Dataset 4 (X, Y) std deviation: (3.3166247903554, 2.031568135925815)


Dataset 1 correlation between X and Y: 0.81642051634484
Dataset 2 correlation between X and Y: 0.81642051634484
Dataset 3 correlation between X and Y: 0.81642051634484
Dataset 4 correlation between X and Y: 0.81642051634484

Todos eles possuem aproximadamente a mesma média, desvio-padrão e correlação. Quão parecidos esses datasets devem ser?

Esse conjunto de datasets são conhecidos como o Quarteto de Anscombe e eles costumam ser usados para ilustrar como confiar apenas em estatísticas como uma forma de caracterizar conjuntos de dados podem induzir a conclusões incorretas.


In [ ]:
# Na primeira vez que o matplotlib é importado, pode ser exibido algum tipo
# de alerta relacionado às fontes do sistema dependendo da sua configuração
import matplotlib.pyplot as plt
# Essa linha permite que os gráficos gerados apareçam diretamente no notebook
# ao invés de serem abertos em uma janela ou arquivo separado.
%matplotlib inline

In [ ]:
# Extraia os preços das casas e a quantidade média de cômodos em duas variáveis separadas
prices = 
rooms = 

# Crie um scatterplot dessas duas features usando plt.scatter()

# Especifique labels para os eixos X e Y

# Exiba o gráfico

In [ ]:
# Extraia os preços das casas e o índice de poluição da vizinhança em duas variáveis separadas
prices = 
nox = 

# Crie um scatterplot dessas duas features usando plt.scatter()

# Especifique labels para os eixos X e Y

# Exiba o gráfico

Previsão de preços

Vimos nos gráficos anteriores que algumas features parecem ter uma relação linear com os preços das casas. Usaremos então a classe LinearRegression to Scikit-Learn para modelar essa relação e conseguir prever preços de casas a partir dessas features.

O exemplo abaixo constrói um modelo LinearRegression usando o número médio de cômodos para prever o preço da casa:


In [ ]:
# Primeiro, extraia os preditores (as features que serão usadas para
# prever o preço das casas) e a saída (os preços das casas) em
# variáveis separadas.

x = # Extraia os valores da coluna 'rm' aqui
y = # Extraia os valores da coluna 'medv' aqui

print('x: {}'.format(x[0:3, :]))
print('y: {}'.format(y[0:3]))

A chamada values.reshape(-1, 1) é necessária nesse caso porque o scikit-learn espera que os preditores estejam na forma de uma matriz - isto é, em um formato de array bidimensional. Como estamos usando apenas um preditor, o pandas acaba representando isso como um array unidimensional, então precisamos "reformatá-lo" em uma "matriz de uma coluna só". Esse passo não é necessário se estivermos usando mais de um preditor para treinar um modelo do scikit-learn, como será visto no próximo exemplo.

Agora que temos o dataset isolado em preditores e saídas, eles precisam ser divididos em dois conjuntos diferentes: um conjunto de treinamento e um conjunto de teste.

Esse passo é necessário caso você precise estimar o quão bem seu modelo treinado se comportará quando for usado para prever preços de novas casas: é necessário usar o conjunto de treinamento para treinar o modelo e então calcular a sua taxa de erros no conjunto de teste.


In [ ]:
# Use a função train_test_split() do scikit-learn para dividir os dados em dois conjuntos.
# http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html
from sklearn.model_selection import train_test_split

RANDOM_STATE = 4321
xtr, xts, ytr, yts = # Chame a função train_test_split aqui

*Se tentarmos estimar a performance do modelo no mesmo conjunto de dados que foi usado para treiná-lo, obteremos uma estimativa enviesada já que o modelo foi treinado para minimizar sua taxa de erro exatamente nos exemplos presentes no conjunto de treinamento. Para estimar corretamente o quão bem o modelo se comportará na prática, ele precisa se testado em um conjunto de dados com o qual ele nunca teve contato.


In [ ]:
from sklearn.linear_model import LinearRegression

lr = # Treine um modelo LinearRegression aqui usando o conjunto de treinamento

lr.predict(6)

In [ ]:
# Calcule os preços previstos pelo modelo treinado
predicted_prices = lr.predict(x)

# Crie um scatterplot dessas duas propriedades usando plt.scatter()
plt.scatter(rooms, prices)
# Crie um line plot exibindo os valores previstos em vermelho
plt.plot(rooms, predicted_prices, 'r')
# Crie labels para os eixos X e Y
plt.xlabel('Number of rooms')
plt.ylabel('House price')
# Exiba o gráfico
plt.show()

Podemos agora usar a função mean_squared_error do Scikit-Learn para calcular o erro total médio do modelo nos dados do conjunto de teste.


In [ ]:
# Use o conjunto de testes para avaliar a performace do modelo
from sklearn.metrics import mean_squared_error

# Calcule o mean_squared_error do modelo aqui

O erro aqui provavelmente será bem alto. Usaremos então todas as features do dataset como preditores para tentar prever os preços das casas e vamos checar o quanto isso melhora a performance do modelo.


In [ ]:
X = # Use o método drop() aqui para descartar a coluna 'medv' e manter as demais.
y = # Extraia o preço das casas aqui a partir da coluna 'medv'.

X.head()

In [ ]:
from sklearn.model_selection import train_test_split

ANOTHER_RANDOM_STATE=1234
# Divida o dataset em treinamente e teste
Xtr, Xts, ytr, yts = 

# Use o conjunto de treinamento para treinar um modelo LinearRegression
lr = 

# Calcule o mean_squared_error do modelo no conjunto de teste aqui

Quais melhorias você acha que ainda poderiam ser feitas para se obter melhores resultados?

Uma observação final sobre a divisão dos dados

Os dados usados em machine learning geralmente são divididos em três partes:

  • Conjunto de treinamento: Os dados usados para se treinar o modelo;
  • Conjunto de validação (não discutido nesse workshop): Esse conjunto é usado para selecionar o melhor modelo dentre diferentes algoritmos ou hiperparâmetros. A ideia é que você não use esse conjunto para treinar seu modelo diretamente, mas sim para selecionar qual algoritmo, valores de hiperparâmetros, etc dão o melhor resultado durante a fase de treinamento;
  • Conjunto de teste: Este é um conjunto usado para estimar a performance do modelo após ter-se treinado e selecionado o modelo final que será usado na prática. Esse conjunto é idealmente usado apenas uma vez para avaliar o quão bem o modelo se comporta quando ele trabalha com dados com os quais ele nunca teve contato antes.

Se quiser mais detalhes, pode checar esse texto(em inglês) para mais informações. Existem outras abordagens bastante populares como Validação cruzada para se fazer seleção e avaliação de modelos mas elas não serão cobertas nesse workshop.